#include "doorbell_ws.h"

#include "esp_websocket_client.h"
#include "freertos/ringbuf.h"
#define TAG "doorbell_ws"

#define AUDIO_WS_URI "ws://192.168.11.5:8000/ws/from_esp"
#define VIDEO_WS_URI "ws://192.168.11.5:8000/ws/image"

esp_websocket_client_handle_t audioWsClient;
esp_websocket_client_handle_t videoWsClient;

RingbufHandle_t ringBuffer;

char taskList[1024];

static void websocket_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
    esp_websocket_event_data_t *data = (esp_websocket_event_data_t *)event_data;
    switch(event_id)
    {
        case WEBSOCKET_EVENT_BEGIN:
            ESP_LOGI(TAG, "WEBSOCKET_EVENT_BEGIN");
            break;
        case WEBSOCKET_EVENT_CONNECTED:
            ESP_LOGI(TAG, "WEBSOCKET_EVENT_CONNECTED");
            break;
        case WEBSOCKET_EVENT_DISCONNECTED:
            ESP_LOGI(TAG, "WEBSOCKET_EVENT_DISCONNECTED");
            break;
        case WEBSOCKET_EVENT_DATA:

            if(data->op_code == 0x2)
            {   // Opcode 0x2 indicates binary data
                // ESP_LOG_BUFFER_HEX("Received binary data", data->data_ptr, data->data_len);
                // MY_LOGI("Received binary data");
                // 把音频数据给es8311进行播放
                doorbell_sound_WriteData((uint8_t *)data->data_ptr, data->data_len);
            }

            break;
        case WEBSOCKET_EVENT_ERROR:
            ESP_LOGI(TAG, "WEBSOCKET_EVENT_ERROR");
            break;
        case WEBSOCKET_EVENT_FINISH:
            ESP_LOGI(TAG, "WEBSOCKET_EVENT_FINISH");
            break;
    }
}

void doorbell_ws_Init(void)
{
    /* 1. 初始化传输音频数据的 ws客户端 */
    esp_websocket_client_config_t websocket_cfg = {
        .uri = AUDIO_WS_URI};
    /*初始化客户端 */
    audioWsClient = esp_websocket_client_init(&websocket_cfg);

    /* 给传输音频的ws客户端注册回调函数 */
    esp_websocket_register_events(audioWsClient, WEBSOCKET_EVENT_ANY, websocket_event_handler, (void *)audioWsClient);

    /* 创建一个环形环形缓冲区，用于mic录制存储音频数据 */
    ringBuffer = xRingbufferCreate(1024 * 8, RINGBUF_TYPE_NOSPLIT);

    /* 2. 初始化传输视频数据的 ws客户端 TODO*/
    websocket_cfg.uri = VIDEO_WS_URI;
    videoWsClient     = esp_websocket_client_init(&websocket_cfg);
}

/**
 * @description: 启动ws客户端, 客户端会自动去连接服务器
 * @param {esp_websocket_client_handle_t} wsClient
 * @return {*}
 */
void doorbell_ws_Start(esp_websocket_client_handle_t wsClient)
{
    /* 客户端已经初始化成功, 并且还没有连接 */
    if(wsClient && esp_websocket_client_is_connected(wsClient) == false)
    {
        MY_LOGE("start wsClient");
        esp_websocket_client_start(wsClient);
    }
}
/**
 * @description: 关闭ws客户端(没有销毁)
 * @param {esp_websocket_client_handle_t} wsClient
 * @return {*}
 */
void doorbell_ws_Stop(esp_websocket_client_handle_t wsClient)
{
    if(wsClient && esp_websocket_client_is_connected(wsClient) == true)
    {
        MY_LOGE("close wsClient");
        esp_websocket_client_close(wsClient, portMAX_DELAY);
    }
}

/**
 * @description: 通过ws发送数据
 * @param {uint8_t} *data
 * @param {int} dataLen
 * @return {*}
 */
void doorbell_ws_SendBinData(esp_websocket_client_handle_t wsClient,
                             uint8_t                      *data,
                             int                           dataLen)
{
    if(wsClient && esp_websocket_client_is_connected(wsClient) == true && data && dataLen)
    {
        esp_websocket_client_send_bin(wsClient, (char *)data, dataLen, 1000);
    }
}

void         mic_buffer_task(void *args);
void         buffer_ws_task(void *args);
TaskHandle_t micBufferTaskHandle;
TaskHandle_t bufferWsTaskHandle;

uint8_t audioCnt   = 0;
uint8_t isDelTask1 = 0;
uint8_t isDelTask2 = 0;
void    doorbell_ws_audio_open(uint8_t dir)
{
    MY_LOGI("打开 客户端 到 门铃 的ws客户端");
    doorbell_ws_Start(audioWsClient);

    audioCnt++;

    /* 如果 dir == DIR_ESP2CLIENT,  启动2个任务,
        任务1: 读取mic的数据, 然后把数据写入到环形缓冲区
        任务2: 从环形缓冲区读取数据, 然后把数据写入到ws客户端
     */
    if(dir == DIR_ESP2CLIENT)
    {
        if(micBufferTaskHandle == NULL)
        {
            xTaskCreate(mic_buffer_task, "mic_buffer_task", 1024 * 4, NULL, 5, &micBufferTaskHandle);
        }

        if(bufferWsTaskHandle == NULL)
        {
            xTaskCreate(buffer_ws_task, "micBufferTaskHandle", 1024 * 4, NULL, 5, &bufferWsTaskHandle);
        }
    }
}

void doorbell_ws_audio_close(uint8_t dir)
{
    if(audioCnt)
    {
        audioCnt--;
    }
    if(audioCnt == 0)
    {
        MY_LOGI("关闭 客户端 到 门铃 的ws客户端");
        doorbell_ws_Stop(audioWsClient);
    }

    if(dir == DIR_ESP2CLIENT)
    {
        /* 删除两个任务 */
        isDelTask1 = 1;
        isDelTask2 = 1;
    }
}

void mic_buffer_task(void *args)
{

    MY_LOGI("mic_buffer_task task start");
    uint8_t data[512 - 8] = {0};
    while(1)
    {
        /* 从mic读取数据, 然后存入到环形缓冲区 */
        doorbell_sound_ReadData(data, sizeof(data));
        /* 向环形缓冲区写数据 */
        xRingbufferSend(ringBuffer, data, sizeof(data), 1000);

        /* 删除任务 */
        if(isDelTask1)
        {
            MY_LOGI("del micbuffer");
            isDelTask1          = 0;
            micBufferTaskHandle = NULL;

            vTaskDelete(NULL);
        }
    }
}

void buffer_ws_task(void *args)
{
    MY_LOGI("buffer_ws_task task start");

    size_t recvDataLen = 0;
    while(1)
    {
        /* 返回值: 读取到的数据的指针地址   */
        uint8_t *data = xRingbufferReceive(ringBuffer, &recvDataLen, 1000);
        if(data)
        {
            /* 通过ws向往发送数据 */
            doorbell_ws_SendBinData(audioWsClient, data, recvDataLen);
            /* 归还内存 */
            vRingbufferReturnItem(ringBuffer, data);
        }

        /* 删除任务 */
        if(isDelTask2)
        {
            MY_LOGI("del bufferWs");
            isDelTask2         = 0;
            bufferWsTaskHandle = NULL;
            vTaskDelete(NULL);
        }
    }
}

void         videoTask(void *args);
TaskHandle_t videoWsTaskHandle;
uint8_t      isDelVideoTask = 0;
void         doorbell_ws_video_open(uint8_t dir)
{

    MY_LOGI("打开 门铃 到 客户端 的ws 视频客户端");
    doorbell_ws_Start(videoWsClient);
    if(videoWsTaskHandle == NULL)
    {
        xTaskCreate(videoTask, "videoTask", 4096, NULL, 5, &videoWsTaskHandle);
    }
}

void doorbell_ws_video_close(uint8_t dir)
{
    isDelVideoTask = 1;
}

void videoTask(void *args)
{
    MY_LOGD("videoTask start");
    uint8_t *buff    = NULL;
    size_t   buffLen = 0;

    TickType_t time = xTaskGetTickCount();
    while(1)
    {
        if(isDelVideoTask)
        {
            isDelVideoTask    = 0;
            videoWsTaskHandle = NULL;
            doorbell_ws_Stop(videoWsClient);
            vTaskDelete(NULL);
        }

        doorbell_video_GetPic(&buff, &buffLen);
        if(buffLen && buff)
        {
            doorbell_ws_SendBinData(videoWsClient, buff, buffLen);

            doorbell_video_ReturnPic();
        }
        vTaskDelayUntil(&time, 30);
    }
}
